package com.ucode.springboot.starter.ESsearch.repository.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;

import org.apache.http.util.EntityUtils;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetRequest;
import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.core.CountRequest;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.mustache.SearchTemplateRequest;
import org.elasticsearch.script.mustache.SearchTemplateResponse;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.SuggestBuilder;
import org.elasticsearch.search.suggest.completion.CompletionSuggestion;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.phrase.DirectCandidateGeneratorBuilder;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestion;
import org.elasticsearch.search.suggest.phrase.PhraseSuggestionBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ucode.springboot.starter.ESsearch.annotation.metadata.ESDocumentData;
import com.ucode.springboot.starter.ESsearch.config.RestHighLevelClientHelper;
import com.ucode.springboot.starter.ESsearch.enums.SqlFormat;
import com.ucode.springboot.starter.ESsearch.repository.BaseElasticsearchTemplate;
import com.ucode.springboot.starter.ESsearch.repository.ElasticsearchSearchTemplate;
import com.ucode.springboot.starter.ESsearch.repository.query.Advanc;
import com.ucode.springboot.starter.ESsearch.repository.query.HighLight;
import com.ucode.springboot.starter.ESsearch.repository.query.PageSortHighLight;
import com.ucode.springboot.starter.ESsearch.repository.query.PhraseSuggestParam;
import com.ucode.springboot.starter.ESsearch.repository.query.Sort;
import com.ucode.springboot.starter.ESsearch.repository.response.ScrollResponse;
import com.ucode.springboot.starter.ESsearch.repository.response.UriResponse;
import com.ucode.springboot.starter.ESsearch.repository.response.UriResponse.HitsBeanX.HitsBean;
import com.ucode.springboot.starter.ESsearch.util.EsTools;
import com.ucode.springboot.starter.ESsearch.util.HttpClientTool;
import com.ucode.tool.base.Paginator;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

@Component
public class ElasticsearchSearchTemplateImpl<T, ID> extends BaseElasticsearchTemplate implements ElasticsearchSearchTemplate<T, ID> {

    @Autowired
    private ObjectMapper objectMapper;
    
    @Autowired
    @Override
    public void setRestHighLevelClientHelper(RestHighLevelClientHelper restHighLevelClientHelper) {
        super.setRestHighLevelClientHelper(restHighLevelClientHelper);
        super.setProperties(restHighLevelClientHelper.getProperties());
    }

    @Override
    public T getById(ID id, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        if (id != null) {
            GetRequest getRequest = buildGetRequest(indexname, id.toString());
            GetResponse getResponse = super.restHighLevelClient.get(getRequest, COMMON_OPTIONS);
            if (getResponse.isExists()) {
                String str = getResponse.getSourceAsString();
                return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str,clazz);
            }
        }
        return null;
    }

    @Override
    public List<T> getByIds(ID[] ids, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        int length = 0;
        List<T> list = null;
        if(ids != null && (length = ids.length) > 0){
            MultiGetRequest request = new MultiGetRequest();
            for (int i = 0; i < length; i++) {
                request.add(new MultiGetRequest.Item(indexname, ids[i].toString()));
            }
            
            MultiGetResponse response = super.restHighLevelClient.mget(request, COMMON_OPTIONS);
            if(response != null && response.getResponses() != null){
                list = new ArrayList<T>();
                for (int i = 0; i < response.getResponses().length; i++) {
                    MultiGetItemResponse item = response.getResponses()[i];
                    GetResponse getResponse = item.getResponse();
                    if (getResponse.isExists()) {
                        String str = getResponse.getSourceAsString();
                        T t = clazz.equals(String.class) ? (T) str : objectMapper.readValue(str,clazz);
                        list.add(t);
                    }
                }
            }
        }
        return list;
    }

    @Override
    public boolean exists(ID id, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        if (id != null) {
            GetRequest getRequest = buildGetRequest(indexname, id.toString());
            GetResponse getResponse = super.restHighLevelClient.get(getRequest, COMMON_OPTIONS);
            return getResponse.isExists();
        }
        return false;
    }

    @Override
    public SearchResponse search(SearchRequest searchRequest) throws Exception {
        SearchResponse searchResponse = super.restHighLevelClient.search(searchRequest, COMMON_OPTIONS);
        return searchResponse;
    }

    @Override
    public List<T> search(QueryBuilder queryBuilder, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return search(queryBuilder, clazz, indexname);
    }

    @Override
    public List<T> search(QueryBuilder queryBuilder, Class<T> clazz, String... indexs) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        SearchRequest searchRequest = buildSearchRequest(queryBuilder, indexname);
        SearchResponse searchResponse = super.restHighLevelClient.search(searchRequest, COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        List<T> list = new ArrayList<T>();
        for (SearchHit hit : searchHits) {
            String str = hit.getSourceAsString();
            T t = clazz.equals(String.class) ? (T) str : objectMapper.readValue(str,clazz);
            list.add(t);
        }
        return list;
    }

    @Override
    public List<T> search(QueryBuilder queryBuilder, int limitSize, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return search(queryBuilder,limitSize,clazz,indexname);
    }

    @Override
    public List<T> search(QueryBuilder queryBuilder, int limitSize, Class<T> clazz, String... indexs) throws Exception {
        PageSortHighLight pageSortHighLight = new PageSortHighLight(1, limitSize);
        Paginator<T> pageList = search(queryBuilder, pageSortHighLight, clazz, indexs);
        if(pageList != null){
            return pageList.getList();
        }
        return null;
    }

    @Override
    public List<T> searchUri(String uri, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        List<T> list = new ArrayList<>();
        Request request = new Request("GET","/"+indexname+"/_search/?"+uri);
        Response response = restHighLevelClient.getLowLevelClient().performRequest(request);
        String responseBody = EntityUtils.toString(response.getEntity());
        if (log.isDebugEnabled()) {
            log.debug("searchUri请求报文："+"/"+indexname+"/_search/?"+uri);
            log.debug("searchUri返回报文："+responseBody);
        }
        UriResponse uriResponse = objectMapper.readValue(responseBody, UriResponse.class);

        List<HitsBean> hitsBeans =  uriResponse.getHits().getHits();
        if(CollUtil.isNotEmpty(hitsBeans)){
            for(HitsBean hitsBean : hitsBeans){
                Object obj = hitsBean.get_source();
                String id = hitsBean.get_id();
                if(obj != null){
                    String str = JSON.toJSONString(obj);
                    T t = (T) objectMapper.readValue(str, clazz);
                    //
                    list.add(t);
                }
            }
        }
        return list;
    }

    @Override
    public String queryBySQL(String sql, SqlFormat sqlFormat) throws Exception {
        List<String> hosts = properties.getClusterNodes();
        if(CollUtil.isEmpty(hosts)){
            throw new Exception("ES cluster nodes is null");
        }
        String ipport = "";
        if(hosts.size() == 1){
            ipport = hosts.get(0);
        }else{//随机选择配置的地址
            int randomindex = new Random().nextInt(hosts.size());
            ipport = hosts.get(randomindex);
        }
        ipport = "http://"+ipport;
        if (log.isDebugEnabled()) {
            log.debug(ipport+"/_sql?format="+sqlFormat.getFormat());
            log.debug("{\"query\":\""+sql+"\"}");
        }
        String username = null;
        String password =  null;
        if(properties.getAccount() != null){
            username = properties.getAccount().getUsername();
            password = properties.getAccount().getPassword();
        }
        
        if(StrUtil.isNotBlank(username)) {
            return HttpClientTool.execute(ipport+"/_sql?format="+sqlFormat.getFormat(),"{\"query\":\""+sql+"\"}",username,password);
        }
        return HttpClientTool.execute(ipport+"/_sql?format="+sqlFormat.getFormat(),"{\"query\":\""+sql+"\"}");
    }

    @Override
    public long count(QueryBuilder queryBuilder, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return count(queryBuilder, clazz, indexname);
    }

    @Override
    public long count(QueryBuilder queryBuilder, Class<T> clazz, String... indexs) throws Exception {
        CountRequest countRequest = new CountRequest(indexs);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        countRequest.source(searchSourceBuilder);
        CountResponse countResponse = super.restHighLevelClient.count(countRequest, COMMON_OPTIONS);
        long count = countResponse.getCount();
        return count;
    }

    @Override
    public Paginator<T> search(QueryBuilder queryBuilder, PageSortHighLight pageSortHighLight, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return search(queryBuilder, pageSortHighLight, clazz, indexname);
    }

    @Override
    public Paginator<T> search(QueryBuilder queryBuilder, PageSortHighLight pageSortHighLight, Class<T> clazz, String... indexs) throws Exception {
        if (pageSortHighLight == null) {
            throw new NullPointerException("[pageSortHighLight] can not be empty !");
        }
        Advanc advanc = new Advanc();
        advanc.setPageSortHighLight(pageSortHighLight);
        return search(queryBuilder,advanc,clazz,indexs);
    }

    @Override
    public Paginator<T> search(QueryBuilder queryBuilder, Advanc advanc, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return search(queryBuilder, advanc, clazz, indexname);
    }

    @Override
    public Paginator<T> search(QueryBuilder queryBuilder, Advanc advanc, Class<T> clazz, String... indexs) throws Exception {
        if (advanc == null) {
            throw new NullPointerException("[advanc] can not be empty !");
        }
        
        Paginator<T> pag = new Paginator<T>();
        PageSortHighLight pageSortHighLight = advanc.getPageSortHighLight();
        
        SearchRequest searchRequest = new SearchRequest(indexs);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(queryBuilder);
        
        boolean highLightFlag = false;
        boolean idSortFlag= false;
        if(pageSortHighLight != null) {
            
            //设置当前页码
            pag.setCurrentPage(pageSortHighLight.getCurrentPage());
            pag.setRows(pageSortHighLight.getPageSize());
            //分页
            if (pageSortHighLight.getPageSize() != 0) {
                //search after不可指定from
                if(!advanc.isSearchAfter()) {
                    searchSourceBuilder.from((pageSortHighLight.getCurrentPage() - 1) * pageSortHighLight.getPageSize());
                }
                searchSourceBuilder.size(pageSortHighLight.getPageSize());
            }
            //排序
            if (pageSortHighLight.getSort() != null) {
                Sort sort = pageSortHighLight.getSort();
                List<Sort.Order> orders = sort.listOrders();
                for (int i = 0; i < orders.size(); i++) {
                    if(orders.get(i).getProperty().equals("_id")){
                        idSortFlag = true;
                    }
                    searchSourceBuilder.sort(new FieldSortBuilder(orders.get(i).getProperty()).order(orders.get(i).getDirection()));
                }
            }
            //高亮
            HighLight highLight = pageSortHighLight.getHighLight();
            if (highLight != null && highLight.getHighLightList() != null && highLight.getHighLightList().size() != 0) {
                HighlightBuilder highlightBuilder = new HighlightBuilder();
                if (StrUtil.isNotBlank(highLight.getPreTag()) && StrUtil.isNotBlank(highLight.getPostTag())) {
                    highlightBuilder.preTags(highLight.getPreTag());
                    highlightBuilder.postTags(highLight.getPostTag());
                }
                for (int i = 0; i < highLight.getHighLightList().size(); i++) {
                    highLightFlag = true;
                    // You can set fragment_size to 0 to never split any sentence.
                    //不对高亮结果进行拆分
                    highlightBuilder.field(highLight.getHighLightList().get(i), 0);
                }
                searchSourceBuilder.highlighter(highlightBuilder);
            }
        }

        
        //设定searchAfter
        if(advanc.isSearchAfter()){
            if(pageSortHighLight == null || pageSortHighLight.getPageSize() == 0){
                searchSourceBuilder.size(10);
            }else{
                searchSourceBuilder.size(pageSortHighLight.getPageSize());
            }
            if(advanc.getSortValues() != null && advanc.getSortValues().length != 0) {
                searchSourceBuilder.searchAfter(advanc.getSortValues());
            }
            //如果没拼_id的排序，自动添加保证排序唯一性
            if(!idSortFlag){
                Sort.Order order = new Sort.Order(SortOrder.ASC,"_id");
                pageSortHighLight.getSort().and(new Sort(order));
                searchSourceBuilder.sort(new FieldSortBuilder("_id").order(SortOrder.ASC));
            }
        }
        
        //设定返回source
        if(advanc.getExcludes()!= null || advanc.getIncludes() != null){
            searchSourceBuilder.fetchSource(advanc.getIncludes(),advanc.getExcludes());
        }
        
        searchRequest.source(searchSourceBuilder);
        //设定routing
        if(StrUtil.isNotBlank(advanc.getRouting())){
            searchRequest.routing(advanc.getRouting());
        }
        
        SearchResponse searchResponse = super.restHighLevelClient.search(searchRequest, COMMON_OPTIONS);
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        
        List<T> list = new ArrayList<T>();
        for (SearchHit hit : searchHits) {
            String str = hit.getSourceAsString();
            
            T t = clazz.equals(String.class) ? (T) str : objectMapper.readValue(str,clazz);
            //替换高亮字段
            if (highLightFlag) {
                Map<String, HighlightField> hmap = hit.getHighlightFields();
                hmap.forEach((k, v) ->{
                    System.err.println("高亮显示->key:"+k+"v:"+v.getFragments()[0]); 
                });
            }
            list.add(t);
        }
        
        pag.setList(list);
        pag.setTotal(hits.getTotalHits().value);
        
        return pag;
    }

    @Override
    public List<String> searchSuggest(String fieldName, String fieldValue, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return searchSuggest(fieldName, fieldValue, clazz, indexname);
    }

    @Override
    public List<String> searchSuggest(String fieldName, String fieldValue, Class<T> clazz, String... indexs) throws Exception {
        String[] indexname = indexs;
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        CompletionSuggestionBuilder completionSuggestionBuilder = new
                CompletionSuggestionBuilder(fieldName + ".suggest");
        completionSuggestionBuilder.text(fieldValue);
        completionSuggestionBuilder.skipDuplicates(true);
        completionSuggestionBuilder.size(COMPLETION_SUGGESTION_SIZE);
        suggestBuilder.addSuggestion("suggest_" + fieldName, completionSuggestionBuilder);
        searchSourceBuilder.suggest(suggestBuilder);
        SearchRequest searchRequest = new SearchRequest(indexname);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = super.restHighLevelClient.search(searchRequest, COMMON_OPTIONS);
        Suggest suggest = searchResponse.getSuggest();
        if (suggest == null) {
            return null;
        }
        CompletionSuggestion completionSuggestion = suggest.getSuggestion("suggest_" + fieldName);
        List<String> list = new ArrayList<>();
        for (CompletionSuggestion.Entry entry : completionSuggestion.getEntries()) {
            for (CompletionSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                list.add(suggestText);
            }
        }
        return list;
    }

    @Override
    public List<String> searchPhraseSuggest(String fieldName, String fieldValue, PhraseSuggestParam param, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return searchPhraseSuggest(fieldName, fieldValue, param, clazz, indexname);
    }

    @Override
    public List<String> searchPhraseSuggest(String fieldName, String fieldValue, PhraseSuggestParam param, Class<T> clazz, String... indexs)
            throws Exception {
        if(param == null){
            //没指定参数，传入默认参数
            param = new PhraseSuggestParam(5,0,null,"always");
        }
        String[] indexname = indexs;
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        SuggestBuilder suggestBuilder = new SuggestBuilder();
        PhraseSuggestionBuilder phraseSuggestionBuilder = new PhraseSuggestionBuilder(fieldName);
        phraseSuggestionBuilder
                .text(fieldValue)
                .confidence(param.getConfidence())
                .size(COMPLETION_SUGGESTION_SIZE)
                .maxErrors(param.getMaxErrors())
                .addCandidateGenerator(new DirectCandidateGeneratorBuilder(fieldName).suggestMode(param.getSuggestMode()));
        if(param.getAnalyzer() != null) {
            phraseSuggestionBuilder.analyzer(param.getAnalyzer());
        }
        suggestBuilder.addSuggestion("suggest_" + fieldName, phraseSuggestionBuilder);
        searchSourceBuilder.suggest(suggestBuilder);
        SearchRequest searchRequest = new SearchRequest(indexname);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = super.restHighLevelClient.search(searchRequest, COMMON_OPTIONS);
        Suggest suggest = searchResponse.getSuggest();
        if (suggest == null) {
            return null;
        }
        PhraseSuggestion phraseSuggestion = suggest.getSuggestion("suggest_" + fieldName);
        List<String> list = new ArrayList<>();
        for (PhraseSuggestion.Entry entry : phraseSuggestion.getEntries()) {
            for (PhraseSuggestion.Entry.Option option : entry) {
                String suggestText = option.getText().string();
                list.add(suggestText);
            }
        }
        return list;
    }

    @Override
    public ScrollResponse<T> createScroll(QueryBuilder queryBuilder, Class<T> clazz, long time, int size) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        return createScroll(queryBuilder,clazz,time,size,indexname);
    }

    @Override
    public ScrollResponse<T> createScroll(QueryBuilder queryBuilder, Class<T> clazz, long time, int size, String... indexs) throws Exception {
        if (queryBuilder == null) {
            queryBuilder = new MatchAllQueryBuilder();
        }
        String[] indexname = indexs;
        List<T> list = new ArrayList<>();
        Scroll scroll = new Scroll(TimeValue.timeValueHours(time));
        SearchRequest searchRequest = new SearchRequest(indexname);
        searchRequest.scroll(scroll);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.size(size);
        searchSourceBuilder.query(queryBuilder);
        searchSourceBuilder.size(DEFAULT_SCROLL_PERPAGE);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = super.restHighLevelClient.search(searchRequest, COMMON_OPTIONS);
        String scrollId = searchResponse.getScrollId();
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        //第一把查询出的结果
        for (SearchHit hit : searchHits) {
            T t = objectMapper.readValue(hit.getSourceAsString(), clazz);
            list.add(t);
        }
        ScrollResponse<T> scrollResponse = new ScrollResponse(list,scrollId);
        return scrollResponse;
    }

    @Override
    public ScrollResponse<T> queryScroll(Class<T> clazz, long time, String scrollId) throws Exception {
        SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
        Scroll scroll = new Scroll(TimeValue.timeValueHours(time));
        scrollRequest.scroll(scroll);
        SearchResponse searchResponse = super.restHighLevelClient.scroll(scrollRequest, COMMON_OPTIONS);
        scrollId = searchResponse.getScrollId();
        SearchHit[] searchHits = searchResponse.getHits().getHits();
        List<T> list = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            T t = objectMapper.readValue(hit.getSourceAsString(), clazz);
            list.add(t);
        }
        ScrollResponse<T> scrollResponse = new ScrollResponse(list,scrollId);
        return scrollResponse;
    }

    @Override
    public Response saveTemplate(String templateName, String templateSource) throws Exception {
        Request scriptRequest = new Request("POST", "_scripts/"+templateName);
        scriptRequest.setJsonEntity(templateSource);
        Response scriptResponse = restHighLevelClient.getLowLevelClient().performRequest(scriptRequest);
        return scriptResponse;
    }

    @Override
    public List<T> searchTemplate(Map<String, Object> templateParams, String templateName, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        SearchTemplateRequest request = new SearchTemplateRequest();
        request.setRequest(new SearchRequest(indexname));

        request.setScriptType(ScriptType.STORED);
        request.setScript(templateName);
        Map<String, Object> params = new HashMap<>();
        if(templateParams != null){
            templateParams.forEach((k,v) -> {
                params.put(k, v);
            });
        }
        request.setScriptParams(params);
        SearchTemplateResponse response = super.restHighLevelClient.searchTemplate(request, COMMON_OPTIONS);
        SearchResponse searchResponse = response.getResponse();
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        List<T> list = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            T t = objectMapper.readValue(hit.getSourceAsString(), clazz);
            list.add(t);
        }
        return list;
    }

    @Override
    public List<T> searchTemplateBySource(Map<String, Object> templateParams, String templateSource, Class<T> clazz) throws Exception {
        ESDocumentData metaData = EsTools.getDocEsIndexMetadata(clazz);
        String indexname = metaData.getIndexname();
        SearchTemplateRequest request = new SearchTemplateRequest();
        request.setRequest(new SearchRequest(indexname));
        request.setScriptType(ScriptType.INLINE);
        request.setScript(templateSource);
        Map<String, Object> scriptParams = new HashMap<>();
        if(templateParams != null){
            templateParams.forEach((k,v) -> {
                scriptParams.put(k, v);
            });
        }
        request.setScriptParams(scriptParams);
        SearchTemplateResponse response = super.restHighLevelClient.searchTemplate(request, COMMON_OPTIONS);
        SearchResponse searchResponse = response.getResponse();
        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHits = hits.getHits();
        List<T> list = new ArrayList<>();
        for (SearchHit hit : searchHits) {
            T t = objectMapper.readValue(hit.getSourceAsString(), clazz);
            list.add(t);
        }
        return list;
    }

}
